/* Copyright Statement:
 *
 * This software/firmware and related documentation ("MediaTek Software") are
 * protected under relevant copyright laws. The information contained herein
 * is confidential and proprietary to MediaTek Inc. and/or its licensors.
 * Without the prior written permission of MediaTek inc. and/or its licensors,
 * any reproduction, modification, use or disclosure of MediaTek Software,
 * and information contained herein, in whole or in part, shall be strictly prohibited.
 *
 * MediaTek Inc. (C) 2010. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
 * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
 * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
 * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
 * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
 * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
 * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
 * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
 * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
 * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
 * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
 * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
 * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
 * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
 *
 * The following software/firmware and/or related documentation ("MediaTek Software")
 * have been modified by MediaTek Inc. All revisions are subject to any receiver's
 * applicable license agreements with MediaTek Inc.
 */

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gionee.navil.lockscreen.shortcut;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Locale;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.location.Location;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StatFs;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.util.Log;

/**
 * {@code ImageManager} is used to retrieve and store images in the media content provider.
 */
@SuppressWarnings("unused")
public class ImageManager {
    private static final String TAG = "ImageManager";

    public static String DCIM = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
            .toString();

    public static String DIRECTORY = DCIM + "/Camera";

    private static final Uri STORAGE_URI = Images.Media.EXTERNAL_CONTENT_URI;

    private static final Uri VIDEO_STORAGE_URI = Uri.parse("content://media/external/video/media");

    private ImageManager() {
    }

    /**
     * {@code ImageListParam} specifies all the parameters we need to create an image list (we also need a
     * ContentResolver).
     */
    public static class ImageListParam implements Parcelable {
        public DataLocation mLocation;
        public int mInclusion;
        public int mSort;
        public String mBucketId;

        // This is only used if we are creating an empty image list.
        public boolean mIsEmptyImageList;

        public ImageListParam() {
        }

        public void writeToParcel(Parcel out, int flags) {
            out.writeInt(mLocation.ordinal());
            out.writeInt(mInclusion);
            out.writeInt(mSort);
            out.writeString(mBucketId);
            out.writeInt(mIsEmptyImageList ? 1 : 0);
        }

        private ImageListParam(Parcel in) {
            mLocation = DataLocation.values()[in.readInt()];
            mInclusion = in.readInt();
            mSort = in.readInt();
            mBucketId = in.readString();
            mIsEmptyImageList = (in.readInt() != 0);
        }

        @Override
        public String toString() {
            return String.format("ImageListParam{loc=%s,inc=%d,sort=%d," + "bucket=%s,empty=%b}", mLocation,
                    mInclusion, mSort, mBucketId, mIsEmptyImageList);
        }

        public static final Parcelable.Creator<ImageListParam> CREATOR = new Parcelable.Creator<ImageListParam>() {
            public ImageListParam createFromParcel(Parcel in) {
                return new ImageListParam(in);
            }

            public ImageListParam[] newArray(int size) {
                return new ImageListParam[size];
            }
        };

        public int describeContents() {
            return 0;
        }
    }

    // Location
    public static enum DataLocation {
        NONE, INTERNAL, EXTERNAL, ALL
    }

    // Inclusion
    public static final int INCLUDE_IMAGES = (1 << 0);
    public static final int INCLUDE_VIDEOS = (1 << 2);

    // Sort
    public static final int SORT_ASCENDING = 1;
    public static final int SORT_DESCENDING = 2;

    public static final String CAMERA_IMAGE_BUCKET_ID = getBucketId(DIRECTORY);

    public static String CAMERA_IMAGE_BUCKET_NAME_EX = null;
    public static String CAMERA_VIDEO_BUCKET_NAME_EX = null;
    public static String CAMERA_IMAGE_BUCKET_ID_EX = null;
    public static String CAMERA_VIDEO_BUCKET_ID_EX = null;

    public static boolean sFileManagerEnabled;

    @SuppressWarnings("deprecation")
    public static boolean getImageBuketNameId(Activity activity) {
        String[] projection = new String[] {"id", "category", "path"};
        Uri allCategory = Uri.parse("content://com.mediatek.filemanager.provider");
        Cursor cur = activity.managedQuery(allCategory, projection, "photo", null, null);
        Cursor curV = activity.managedQuery(allCategory, projection, "video", null, null);
        if (cur != null && cur.moveToFirst()) {
            do {
                CAMERA_IMAGE_BUCKET_NAME_EX = cur.getString(cur.getColumnIndex("path"));
            } while (cur.moveToNext());
        }
        if (curV != null && curV.moveToFirst()) {
            do {
                CAMERA_VIDEO_BUCKET_NAME_EX = curV.getString(curV.getColumnIndex("path"));
            } while (curV.moveToNext());
        }

        if (CAMERA_IMAGE_BUCKET_NAME_EX != null && CAMERA_VIDEO_BUCKET_NAME_EX != null) {
            CAMERA_IMAGE_BUCKET_ID_EX = getBucketId(CAMERA_IMAGE_BUCKET_NAME_EX);
            CAMERA_VIDEO_BUCKET_ID_EX = getBucketId(CAMERA_VIDEO_BUCKET_NAME_EX);
        }

        Log.v(TAG, "photo path: " + CAMERA_IMAGE_BUCKET_NAME_EX);
        Log.v(TAG, "video path: " + CAMERA_VIDEO_BUCKET_NAME_EX);

        if (CAMERA_IMAGE_BUCKET_NAME_EX != null && CAMERA_VIDEO_BUCKET_NAME_EX != null
                && CAMERA_IMAGE_BUCKET_ID_EX != null && CAMERA_VIDEO_BUCKET_ID_EX != null) {
            sFileManagerEnabled = true;
            return true;
        } else {
            return false;
        }

    }

    /**
     * Matches code in MediaProvider.computeBucketValues. Should be a common function.
     */
    public static String getBucketId(String path) {
        return String.valueOf(path.toLowerCase(Locale.ENGLISH).hashCode());
    }

    /**
     * OSX requires plugged-in USB storage to have path /DCIM/NNNAAAAA to be imported. This is a temporary fix
     * for bug#1655552.
     */
    public static void ensureOSXCompatibleFolder() {
        File nnnAAAAA = new File(Environment.getExternalStorageDirectory().toString() + "/DCIM/100ANDRO");
        if ((!nnnAAAAA.exists()) && (!nnnAAAAA.mkdir())) {
            Log.e(TAG, "create NNNAAAAA file: " + nnnAAAAA.getPath() + " failed");
        }
    }

    //
    // Stores a bitmap or a jpeg byte array to a file (using the specified
    // directory and filename). Also add an entry to the media store for
    // this picture. The title, dateTaken, location are attributes for the
    // picture. The degree is a one element array which returns the orientation
    // of the picture.
    //
    public static Uri addImage(ContentResolver cr, String title, long dateTaken, Location location,
            String directory, String filename, Bitmap source, byte[] jpegData, int[] degree) {
        // We should store image data earlier than insert it to ContentProvider,
        // otherwise we may not be able to generate thumbnail in time.
        Log.i(TAG, "write jpeg data to file");
        OutputStream outputStream = null;
        String filePath = directory + "/" + filename;
        try {
            File dir = new File(directory);
            if (!dir.exists())
                dir.mkdirs();
            File file = new File(directory, filename);
            outputStream = new FileOutputStream(file);
            if (source != null) {
                source.compress(CompressFormat.JPEG, 75, outputStream);
                degree[0] = 0;
            } else {
                outputStream.write(jpegData);
                degree[0] = getExifOrientation(filePath);
            }
        } catch (FileNotFoundException ex) {
            Log.w(TAG, ex);
            return null;
        } catch (IOException ex) {
            Log.w(TAG, ex);
            return null;
        } finally {
            Util.closeSilently(outputStream);
        }
        Log.i(TAG, "write jpeg end");

        // Read back the compressed file size.
        long size = new File(directory, filename).length();

        ContentValues values = new ContentValues(9);
        values.put(Images.Media.TITLE, title);

        // That filename is what will be handed to Gmail when a user shares a
        // photo. Gmail gets the name of the picture attachment from the
        // "DISPLAY_NAME" field.
        values.put(Images.Media.DISPLAY_NAME, filename);
        values.put(Images.Media.DATE_TAKEN, dateTaken);
        values.put(Images.Media.MIME_TYPE, "image/jpeg");
        values.put(Images.Media.ORIENTATION, degree[0]);
        values.put(Images.Media.DATA, filePath);
        values.put(Images.Media.SIZE, size);

        if (location != null) {
            values.put(Images.Media.LATITUDE, location.getLatitude());
            values.put(Images.Media.LONGITUDE, location.getLongitude());
        }

        return cr.insert(STORAGE_URI, values);

    }

    public static int getExifOrientation(String filepath) {
        int degree = 0;
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
        } catch (IOException ex) {
            Log.e(TAG, "cannot read exif", ex);
        }
        if (exif != null) {
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
            if (orientation != -1) {
                // We only recognize a subset of orientation tag values.
                switch (orientation) {
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        degree = 90;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        degree = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        degree = 270;
                        break;
                }

            }
        }
        return degree;
    }

    public static Uri addImage(ContentResolver cr, String title, long dateTaken, Location location,
            String directory, String newfilename, String oldFileName, int[] degree, boolean isMpo) {
        // We should store image data earlier than insert it to ContentProvider, otherwise
        // we may not be able to generate thumbnail in time.
        String newPathName = directory + "/" + newfilename;
        File fOld = new File(oldFileName);
        File fNew = new File(newPathName);

        fOld.renameTo(fNew);

        degree[0] = getExifOrientation(newPathName);

        ContentValues values = new ContentValues(7);
        values.put(Images.Media.TITLE, title);

        // That filename is what will be handed to Gmail when a user shares a
        // photo. Gmail gets the name of the picture attachment from the
        // "DISPLAY_NAME" field.
        values.put(Images.Media.DISPLAY_NAME, newfilename);
        values.put(Images.Media.DATE_TAKEN, dateTaken);
        values.put(Images.Media.MIME_TYPE, isMpo ? "image/mpo" : "image/jpeg");
        values.put(Images.Media.ORIENTATION, degree[0]);
        values.put(Images.Media.DATA, newPathName);

        // Since we have media size already we can directly add it.
        values.put(Images.Media.SIZE, fNew.length());

        if (location != null) {
            values.put(Images.Media.LATITUDE, location.getLatitude());
            values.put(Images.Media.LONGITUDE, location.getLongitude());
        }

        return cr.insert(STORAGE_URI, values);
    }

    public static ImageListParam getImageListParam(DataLocation location, int inclusion, int sort,
            String bucketId) {
        ImageListParam param = new ImageListParam();
        param.mLocation = location;
        param.mInclusion = inclusion;
        param.mSort = sort;
        param.mBucketId = bucketId;
        return param;
    }

    private static boolean checkFsWritable() {
        // Create a temporary file to see whether a volume is really writeable.
        // It's important not to put it in the root directory which may have a
        // limit on the number of files.
        String directoryName = Environment.getExternalStorageDirectory().toString() + "/DCIM";
        File directory = new File(directoryName);
        if (!directory.isDirectory()) {
            if (!directory.mkdirs()) {
                return false;
            }
        }
        return directory.canWrite();
    }

    public static boolean hasStorage() {
        return hasStorage(true);
    }

    public static boolean hasStorage(boolean requireWriteAccess) {
        String state = Environment.getExternalStorageState();

        if (Environment.MEDIA_MOUNTED.equals(state)) {
            if (requireWriteAccess) {
                boolean writable = checkFsWritable();
                if (!writable && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) && !hasFreeSpace()) {
                    // not writeable due to disk full, assume is as has a writable storage
                    // and pop disk full error later
                    Log.v(TAG, "not writeable due to disk full");
                    return true;
                }
                return writable;
            } else {
                return true;
            }
        } else if (!requireWriteAccess && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            return true;
        }
        return false;
    }

    public static boolean hasFreeSpace() {
        String state = Environment.getExternalStorageState();

        if (Environment.MEDIA_MOUNTED.equals(state)) {
            String storageDirectory = Environment.getExternalStorageDirectory().toString();
            StatFs stat = new StatFs(storageDirectory);
            return (stat.getAvailableBlocks() > 0);
        }
        return false;
    }

    private static Cursor query(ContentResolver resolver, Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        try {
            if (resolver == null) {
                return null;
            }
            return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
        } catch (UnsupportedOperationException ex) {
            return null;
        }

    }

    public static boolean isMediaScannerScanning(ContentResolver cr) {
        boolean result = false;
        Cursor cursor = query(cr, MediaStore.getMediaScannerUri(),
                new String[] {MediaStore.MEDIA_SCANNER_VOLUME}, null, null, null);
        if (cursor != null) {
            if (cursor.getCount() == 1) {
                cursor.moveToFirst();
                result = "external".equals(cursor.getString(0));
            }
            cursor.close();
        }

        return result;
    }

    public static String getLastImageThumbPath() {

        return Environment.getExternalStorageDirectory().toString() + "/DCIM/.thumbnails/image_last_thumb";

    }

    public static String getLastVideoThumbPath() {
        return Environment.getExternalStorageDirectory().toString() + "/DCIM/.thumbnails/video_last_thumb";
    }

    public static String getTempJpegPath() {
        return Environment.getExternalStorageDirectory().toString() + "/DCIM/.tempjpeg";
    }

    public static boolean ensureImageBucketFolder() {
        File bucket;
        if (!sFileManagerEnabled) {
            bucket = new File(DIRECTORY);
        } else {
            bucket = new File(CAMERA_IMAGE_BUCKET_NAME_EX);
        }
        if ((!bucket.exists()) && (!bucket.mkdir())) {
            Log.e(TAG, "create Image Bucket " + bucket.getPath() + " failed");
            return false;
        }
        return true;
    }

    public static String getImageBucketName() {
        return DIRECTORY;
    }

    public static String getImageBucketId() {
        if (!sFileManagerEnabled) {
            return CAMERA_IMAGE_BUCKET_ID;
        } else {
            return CAMERA_IMAGE_BUCKET_ID_EX;
        }
    }

    public static String getVideoBucketName() {
        return DIRECTORY;
    }

    public static String getVideoBucketId() {
        if (!sFileManagerEnabled) {
            return CAMERA_IMAGE_BUCKET_ID;
        } else {
            return CAMERA_VIDEO_BUCKET_ID_EX;
        }
    }

}
